#include "messagehandler.h"
#include <iostream>
#include <sstream>
#include "protocol.h"

namespace client_server{
	using namespace std;
	using namespace protocol;
	MessageHandler::MessageHandler(){}

	//Will read the message on the connection and print it on the stringstream
	void MessageHandler::read(Connection* goal, stringstream& ss){
		unsigned char mess = goal->read();
		switch (mess){
			case Protocol::COM_LIST_NG:
				mess = goal->read();				
				if(mess == Protocol::COM_END)
					//ss << "COM_LIST_NG";
					ss << Protocol::COM_LIST_NG << " ";
				else
					cout<<"error"<<endl;
			break;
			case Protocol::COM_CREATE_NG:
				//ss << "COM_CREATE_NG";
				ss << Protocol::COM_CREATE_NG << " ";
				readParameters(goal, ss);
			break;
			case Protocol::COM_DELETE_NG:
				//ss << "COM_DELETE_NG";
				ss << Protocol::COM_DELETE_NG << " ";
				readParameters(goal, ss);
			break;
			case Protocol::COM_LIST_ART:
				//ss << "COM_LIST_ART";
				ss << Protocol::COM_LIST_ART << " ";
				readParameters(goal, ss);
			break;
			case Protocol::COM_CREATE_ART:
				//ss << "COM_CREATE_ART";
				ss << Protocol::COM_CREATE_ART << " ";
				readParameters(goal, ss);
			break;
			case Protocol::COM_DELETE_ART:
				//ss << "COM_DELETE_ART";
				ss << Protocol::COM_DELETE_ART << " ";
				readParameters(goal, ss);
			break;
			case Protocol::COM_GET_ART:
				//ss << "COM_GET_ART";
				ss << Protocol::COM_GET_ART << " ";
				readParameters(goal, ss);
			break;
			case Protocol::ANS_LIST_NG:
				//ss << "ANS_LIST_NG";
				ss << Protocol::ANS_LIST_NG << " ";
				readParameters(goal, ss);
			break;
			case Protocol::ANS_CREATE_NG:
				//ss << "ANS_CREATE_NG";
				ss << Protocol::ANS_CREATE_NG << " ";
				read(goal, ss);
			break;
			case Protocol::ANS_DELETE_NG:
				//ss << "ANS_DELETE_NG";
				ss << Protocol::ANS_DELETE_NG << " ";
				read(goal, ss);
			break;
			case Protocol::ANS_LIST_ART:
				//ss << "ANS_LIST_ART";
				ss << Protocol::ANS_LIST_ART << " ";
				read(goal, ss);
			break;
			case Protocol::ANS_CREATE_ART:
				//ss << "ANS_CREATE_ART";
				ss << Protocol::ANS_CREATE_ART << " ";
				read(goal, ss);
			break;
			case Protocol::ANS_DELETE_ART:
				//ss << "ANS_DELETE_ART";
				ss << Protocol::ANS_DELETE_ART << " ";
				read(goal, ss);
			break;
			case Protocol::ANS_GET_ART:
				//ss << "ANS_GET_ART";
				ss << Protocol::ANS_GET_ART << " ";
				read(goal, ss);
			break;
			case Protocol::ANS_ACK:
				//ss << "ANS_ACK";
				ss << Protocol::ANS_ACK << " ";
				readParameters(goal, ss);
			break;
			case Protocol::ANS_NAK:
				//ss << "ANS_NAK";
				ss << Protocol::ANS_NAK << " ";
				readError(goal, ss);
			break;

			default: cout << "Incorrect format on message" << endl;;
    		break;
		}
	}

	//Will read all parameters and print them to the stringstream until ANS_END or COM_END is encountered.
	void MessageHandler::readParameters(Connection* goal, stringstream& ss){
		//cout<<"Read parameter"<<endl;
		unsigned char value = goal->read();
		if(value != Protocol::ANS_END && value != Protocol::COM_END){
			if(value == Protocol::PAR_STRING){
				unsigned char byte1 = goal->read();
    			unsigned char byte2 = goal->read();
    			unsigned char byte3 = goal->read();
    			unsigned char byte4 = goal->read();
    			int n = (byte1 << 24) | (byte2 << 16) | (byte3 << 8) | byte4;
				ss << n << " ";
				for(int i = 0; i < n; i++){
					value = goal->read();
					ss << value;
				}
				ss << " ";
				readParameters(goal, ss);
			}
			else if(value == Protocol::PAR_NUM){
				unsigned char byte1 = goal->read();
    			unsigned char byte2 = goal->read();
    			unsigned char byte3 = goal->read();
    			unsigned char byte4 = goal->read();
    			int n = (byte1 << 24) | (byte2 << 16) | (byte3 << 8) | byte4;
				ss << n << " ";
				readParameters(goal, ss);
			}
			else{cout << "Parameters missing" << endl;}
		}
	}

	//Will read the error flag from the server
	void MessageHandler::readError(Connection* goal, stringstream& ss){
		cout<<"Read error"<<endl;
		
		unsigned char value = goal->read();
		switch(value){
			case Protocol::ERR_NG_ALREADY_EXISTS:
				ss << Protocol::ERR_NG_ALREADY_EXISTS;
			break;
			case Protocol::ERR_NG_DOES_NOT_EXIST:
				ss << Protocol::ERR_NG_DOES_NOT_EXIST;
			break;
			case Protocol::ERR_ART_DOES_NOT_EXIST:
				ss << Protocol::ERR_ART_DOES_NOT_EXIST;
			break;
			
			default: cout << "Error missing" << endl;;
		}
	}

	//Send a byte on the connection
	void MessageHandler::sendByte(Connection* goal, char code){
		goal->write(code);
	}

	//Send an int value on the connection
	void MessageHandler::sendInt(Connection* goal, int value){
		goal->write((value >> 24) & 0xFF);
		goal->write((value >> 16) & 0xFF);
		goal->write((value >> 8) & 0xFF);
		goal->write(value & 0xFF);
	}

	//Send an int as a parameter on the connection
	void MessageHandler::sendIntParameter(Connection* goal, int value){
		sendByte(goal, Protocol::PAR_NUM);
		sendInt(goal, value);	
	}

	//Send a string/stringstream as a parameter on the connection
	void MessageHandler::sendStringParameter(Connection* goal, string s){
		sendByte(goal, Protocol::PAR_STRING);
		sendInt(goal, s.size());
		unsigned int i;
		for(i = 0; i < s.size(); i++){
			sendByte(goal, s[i]);
		}
	}
}
